from typing import List, Optional, Dict, Tuple
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, insert, update, delete, and_
from sqlalchemy.orm import selectinload

from basic.models import (
    LogicalRepository,
    LogicalEntry,
    RelationRepoEntry
)
from basic.database import generate_random_string

async def create_repo(db: AsyncSession, name: str) -> Tuple[LogicalRepository, str]:
    """
    创建一个仓库和其根目录条目
    
    Args:
        db: 数据库会话
        name: 仓库名称
        
    Returns:
        Tuple[LogicalRepository, str]: 创建的仓库和根条目的key
    """
    # 生成随机键
    repo_key = generate_random_string(4)
    entry_key = generate_random_string(8)
    
    # 创建仓库
    repo_stmt = (
        insert(LogicalRepository)
        .values(
            key=repo_key,
            name=name,
        )
        .returning(LogicalRepository)
    )
    result = await db.execute(repo_stmt)
    new_repo = result.scalar_one()
    
    # 创建根目录条目
    entry_stmt = (
        insert(LogicalEntry)
        .values(
            key=entry_key,
            path="/",
            is_directory=True,
            parent_id=None
        )
        .returning(LogicalEntry)
    )
    await db.execute(entry_stmt)
    
    # 创建关联
    relation_stmt = (
        insert(RelationRepoEntry)
        .values(
            repository_key=repo_key,
            entry_key=entry_key
        )
    )
    await db.execute(relation_stmt)
    
    return new_repo, entry_key

async def delete_repo(db: AsyncSession, repo_key: str) -> Optional[LogicalRepository]:
    """
    删除仓库及其关联
    
    Args:
        db: 数据库会话
        repo_key: 仓库键
        
    Returns:
        Optional[LogicalRepository]: 被删除的仓库，如果不存在则返回None
    """
    # 查询仓库以便返回
    select_stmt = select(LogicalRepository).where(LogicalRepository.key == repo_key)
    result = await db.execute(select_stmt)
    repo = result.scalar_one_or_none()
    
    if not repo:
        return None
    
    # 删除仓库与条目的关联
    relation_stmt = delete(RelationRepoEntry).where(
        RelationRepoEntry.repository_key == repo_key
    )
    await db.execute(relation_stmt)
    
    # 删除仓库
    repo_stmt = delete(LogicalRepository).where(
        LogicalRepository.key == repo_key
    )
    await db.execute(repo_stmt)
    
    return repo

async def update_repo_name(db: AsyncSession, repo_key: str, name: str) -> Optional[LogicalRepository]:
    """
    更新仓库名称
    
    Args:
        db: 数据库会话
        repo_key: 仓库键
        name: 新名称
        
    Returns:
        Optional[LogicalRepository]: 更新后的仓库，如果不存在则返回None
    """
    stmt = select(LogicalRepository).where(LogicalRepository.key == repo_key)
    result = await db.execute(stmt)
    repo = result.scalar_one_or_none()
    
    if not repo:
        return None
    
    repo.name = name
    await db.commit()
    await db.refresh(repo)
    return repo
    

async def get_repo(db: AsyncSession, repo_key: str) -> Optional[LogicalRepository]:
    """
    获取单个仓库
    
    Args:
        db: 数据库会话
        repo_key: 仓库键
        
    Returns:
        Optional[LogicalRepository]: 查询到的仓库，如果不存在则返回None
    """
    stmt = select(LogicalRepository).where(LogicalRepository.key == repo_key)
    result = await db.execute(stmt)
    return result.scalar_one_or_none()

async def get_repos(db: AsyncSession) -> List[Tuple[LogicalRepository, LogicalEntry]]:
    """
    获取所有仓库及其根目录条目
    
    Args:
        db: 数据库会话
        
    Returns:
        List[Tuple[LogicalRepository, LogicalEntry]]: 仓库和根目录条目列表
    """
    stmt = (
        select(LogicalRepository, LogicalEntry)
        .select_from(LogicalRepository)
        .join(
            RelationRepoEntry,
            RelationRepoEntry.repository_key == LogicalRepository.key
        )
        .join(
            LogicalEntry,
            RelationRepoEntry.entry_key == LogicalEntry.key
        )
        .where(LogicalEntry.path == "/")
        .order_by(LogicalRepository.created_at.desc())
    )
    
    result = await db.execute(stmt)
    return result.all()

async def get_repo_root_entry(db: AsyncSession, repo_key: str) -> Optional[LogicalEntry]:
    """
    获取仓库的根目录条目
    
    Args:
        db: 数据库会话
        repo_key: 仓库键
        
    Returns:
        Optional[LogicalEntry]: 根目录条目，如果不存在则返回None
    """
    stmt = (
        select(LogicalEntry)
        .select_from(LogicalRepository)
        .join(
            RelationRepoEntry,
            RelationRepoEntry.repository_key == LogicalRepository.key
        )
        .join(
            LogicalEntry,
            RelationRepoEntry.entry_key == LogicalEntry.key
        )
        .where(
            and_(
                LogicalRepository.key == repo_key,
                LogicalEntry.path == "/"
            )
        )
    )
    
    result = await db.execute(stmt)
    return result.scalar_one_or_none() 